#include "StdAfx.h"
#include "GraphicFactory.h"
#include "Animation.h"

namespace Graphics
{
	Animation::Animation(void):
		m_IsPlaying(true),
		m_Delay(0),
		m_NowFrame(-1),
		m_pFrame(0),
		m_Speed(1.0f),
		m_State(ANI_PLAYING),
		m_Pos(0,0)
	{
	}

	Animation::~Animation(void)
	{
		for(vector<Frame*>::iterator i = m_Frames.begin(); i != m_Frames.end();i++)
		{
			delete (*i);
		}
		for(vector<AniTexture*>::iterator i = m_Textures.begin(); i != m_Textures.end();i++)
		{
			delete (*i);
		}
	}

	bool Animation::LoadXML(const MSXML2::IXMLDOMNodePtr& pNode)
	{
		try
		{
			m_Name = pNode->attributes->getNamedItem("name")->text;
			MSXML2::IXMLDOMNodePtr pFrameNode = pNode->selectSingleNode("Frames");
			MSXML2::IXMLDOMNodeListPtr pFrameList = pFrameNode->selectNodes("Frame");
			for(int i=0;i<pFrameList->length;i++)
			{
				Frame* pFrame = new Frame(pFrameList->item[i]);
				m_Frames.push_back(pFrame);
			}

			MSXML2::IXMLDOMNodePtr pTextureNode = pNode->selectSingleNode("Textures");			
			MSXML2::IXMLDOMNodeListPtr pTextureList = pTextureNode->selectNodes("Texture");
			for(int i=0;i<pTextureList->length;i++)
			{
				int row = atoi(pTextureList->item[i]->attributes->getNamedItem("row")->text);
				int col = atoi(pTextureList->item[i]->attributes->getNamedItem("col")->text);
				

				std::string filename = (std::string)pTextureList->item[i]->attributes->getNamedItem("file")->text;
				Drawable* bitmap = GraphicFactory::getInstance()->GetDrawableFromCache(filename);
				AniTexture* pT = new AniTexture(row,col,bitmap);				
				m_Textures.push_back(pT);
			}

			pTextureList.Release();
			pTextureNode.Release();
			pFrameList.Release();
			pFrameNode.Release();
			
			return true;
		}
		catch(...)
		{
			return false;
		}
	}
	
	bool Animation::Load(std::string filename)
	{
		
		HRESULT hr;
		MSXML2::IXMLDOMDocumentPtr pDoc;
		
		CoInitialize(NULL);
		hr= pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));
		if (FAILED(hr)) 
		{
			return false;
		}

		// The default is true.
		pDoc->async = VARIANT_FALSE;
		
		// Load a xml file
		if(pDoc->load((_variant_t)filename.c_str())!=VARIANT_TRUE)
		{
		  return false;
		}
		
		MSXML2::IXMLDOMNodePtr	pRootNode = pDoc->selectSingleNode("Animation");

		m_Delay = 0;
		m_NowFrame = -1;

		bool result = this->LoadXML(pRootNode);

		pRootNode.Release();
		pDoc.Release();
		CoUninitialize();
		
		return result;
	}


	ANI_STATE Animation::GetState(void)
	{
		return m_State;
	}
	
	bool Animation::Render(Graphic* pGraphic)
	{
		if(m_IsPlaying)
		{
			m_Delay --;

			// play next frame
			if(m_Delay <= 0)
			{
				m_NowFrame ++;
				if(m_NowFrame < 0 || m_NowFrame >= (int)m_Frames.size())
				{
					m_NowFrame = 0;
				}
				m_pFrame = m_Frames[m_NowFrame];
				m_Delay = m_pFrame->delay;
			}
		}
		for(vector<Image*>::iterator i=m_pFrame->images.begin(); i != m_pFrame->images.end();i++)
		{
			m_Textures[(*i)->texture_id]->SetIndex((*i)->tile_id);
			m_Textures[(*i)->texture_id]->SetPos((*i)->x,(*i)->y);
			m_Textures[(*i)->texture_id]->Render(pGraphic);
		}
		
		return true;
	}

	ANI_STATE Animation::Play(void)
	{
		m_IsPlaying = true;
		return m_State = ANI_PLAYING;
	}

	ANI_STATE Animation::Stop(void)
	{
		m_IsPlaying = false;
		return m_State = ANI_STOP;
	}

	bool Animation::SetFrame(int frame)
	{
		if(frame >= 0 && frame < (int)m_Frames.size())
		{
			m_NowFrame = frame;
			m_pFrame = m_Frames[m_NowFrame];
			m_Delay = m_pFrame->delay;
			return true;
		}
		return false;
	}

	float Animation::GetSpeed(void)
	{
		return m_Speed;
	}

	void Animation::SetSpeed(float speed)
	{
		m_Speed = speed;
	}

	const Position& Animation::GetPos(void)
	{
		return m_Pos;
	}

	void Animation::SetPos(int x,int y)
	{
		m_Pos.Set(x,y);
	}
	const std::string& Animation::GetName(void)
	{
		return m_Name;
	}
}

namespace Graphics
{

	Animation::Image::Image(void):texture_id(0),tile_id(0),x(0),y(0)
	{
	}
	Animation::Image::Image(const MSXML2::IXMLDOMNodePtr& pNode)
	{
		if(!this->LoadXML(pNode))
		{
			throw(std::exception("Image uninitialize!"));
		}
	}
	bool Animation::Image::LoadXML(const MSXML2::IXMLDOMNodePtr& pNode)
	{
		try
		{
			texture_id = atoi(pNode->attributes->getNamedItem("texture_id")->text);
			tile_id = atoi(pNode->attributes->getNamedItem("tile_id")->text);
			x = atoi(pNode->attributes->getNamedItem("x")->text);
			y = atoi(pNode->attributes->getNamedItem("y")->text);
			return true;
		}
		catch(...)
		{
			texture_id = 0;
			tile_id = 0;
			x = 0;
			y = 0;
			return false;
		}
	}

	Animation::Frame::Frame(const MSXML2::IXMLDOMNodePtr& pNode)
	{
		if(!this->LoadXML(pNode))
		{
			throw(std::exception("Frame uninitialize!"));
		}
	}
	Animation::Frame::~Frame(void)
	{
		for(vector<Image*>::iterator i = images.begin(); i!= images.end();i++)
		{
			delete (*i);
		}
	}
	bool Animation::Frame::LoadXML(const MSXML2::IXMLDOMNodePtr& pNode)
	{
		try
		{
			MSXML2::IXMLDOMNodeListPtr pNodeList = pNode->selectNodes("Image");
			delay = atoi(pNode->attributes->getNamedItem("delay")->text);
			for(int i=0;i<pNodeList->length;i++)
			{
				Image* pImage = new Image(pNodeList->item[i]);
				images.push_back(pImage);
			}
			pNodeList.Release();
			return true;
		}
		catch(...)
		{
			return false;
		}
	}

	Animation::AniTexture::AniTexture(DWORD col,DWORD row,Drawable* bitmap):SpriteTile(col,row,bitmap),m_Pos(0,0)
	{
		m_Data.pData = new DWORD[1];
		m_Data.pStep = 0;
		m_Data.width = 1;
		m_Data.count = 1;
		this->SetIndex(0);
	}

	Animation::AniTexture::~AniTexture(void)
	{
		delete m_Data.pData;
	}

	const Position& Animation::AniTexture::GetPos(void)
	{
		return m_Pos;
	}

	const SpriteTile::TileData& Animation::AniTexture::GetData(void)
	{
		return m_Data;
	}

	void Animation::AniTexture::SetIndex(DWORD i)
	{
		m_Data.pData[0] = i;
	}

	void Animation::AniTexture::SetPos(int x,int y)
	{
		m_Pos.Set(x,y);
	}
}